Add copy-to-output-directory MSBuild skill (IfDifferent / SkipUnchangedFilesOnCopyAlways) - #883
Conversation
There was a problem hiding this comment.
Pull request overview
Adds a new dotnet-msbuild skill, copy-to-output-directory, to document MSBuild’s copy-to-output/publish metadata modes (including the newer IfDifferent mode and $(SkipUnchangedFilesOnCopyAlways)), and wires the skill into existing agent routing so it can be recommended during troubleshooting, code review, and build performance work.
Changes:
- Added a new skill doc:
copy-to-output-directory(mode comparison,IfDifferentsemantics, and version gating guidance). - Updated
msbuild,msbuild-code-review, andbuild-perfagents to reference the new skill for routing and specialization.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| plugins/dotnet-msbuild/skills/copy-to-output-directory/SKILL.md | New skill documentation covering CopyToOutputDirectory/CopyToPublishDirectory mode selection and MSBuild 17.13+ features. |
| plugins/dotnet-msbuild/agents/msbuild.agent.md | Adds routing and skill list entry for the new copy-to-output-directory skill. |
| plugins/dotnet-msbuild/agents/msbuild-code-review.agent.md | Adds the new skill to the companion skills reference list. |
| plugins/dotnet-msbuild/agents/build-perf.agent.md | Adds the new skill to the performance-focused specialized skills reference list. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Adds a focused dotnet-msbuild skill documenting how to choose a CopyToOutputDirectory / CopyToPublishDirectory mode, including the `IfDifferent` mode and the `$(SkipUnchangedFilesOnCopyAlways)` property introduced in MSBuild 17.13 / .NET SDK 9.0.2xx (dotnet/msbuild#11052). Covers mode semantics (Never/PreserveNewest/Always/IfDifferent), why `Always` is a per-build perf hit, the SkipUnchangedFiles timestamp+size comparison, transitive copy through ProjectReference, and version requirements. Registers the skill in the msbuild, msbuild-code-review, and build-perf agent routing lists. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 881d26ad-87b7-48e3-8ec6-043163944437
2875d0e to
a608f8e
Compare
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Skill Validation ResultsModel: claude-opus-4.6 | Judge: claude-opus-4.6 🔍 Full Results - additional metrics and failure investigation steps ▶ Sessions Visualisation -- interactive replay of all evaluation sessions |
|
✅ Evaluation passed for |
Evangelink
left a comment
There was a problem hiding this comment.
Reviewed in depth — approving. Verified every technical claim against the live dotnet/msbuild Microsoft.Common.CurrentVersion.targets:
- Target names
_CopyOutOfDateSourceItemsToOutputDirectoryAlways,_CopyDifferingSourceItemsToOutputDirectory, and_CopyToOutputDirectoryTransitiveItems— exact match. $(SkipUnchangedFilesOnCopyAlways)defaults tofalseand is passed asSkipUnchangedFiles="$(SkipUnchangedFilesOnCopyAlways)"on theAlwaystarget — correct.IfDifferenttarget usesSkipUnchangedFiles="true"(timestamp + size heuristic) — correct, and the doc's careful "not a content hash" wording is accurate.FileWritesregistration, transitive copy viaProjectReference, and ClickOnce inclusion ofIfDifferentalongsideAlways/PreserveNewest— all confirmed.- Version claim (MSBuild 17.13 / SDK 9.0.2xx / dotnet/msbuild#11052, merged 2024-12-05) — accurate.
Non-blocking notes for consideration:
-
Skill-menu budget headroom (heads-up). Using the validator's exact
RenderedSkillMenuCostformula, this bringsdotnet-msbuildto 14,953 / 15,000 chars — only ~47 chars of headroom. It passescheck, but given the recentrestore-15k-skill-budgetwork, any later skill or a small description tweak will tip the plugin over and silently truncate the alphabetically-last skill's description. Might be worth reclaiming a few chars from an over-long sibling description (e.g.property-patterns~975,target-authoring~929) at some point. -
Description routing pattern. 16/18 sibling skills use the
USE FOR:/DO NOT USE FOR:pattern for routing. This one uses a plain sentence — reasonable given the budget pressure above, just flagging it as an intentional trade-off. -
Minor wording. "GetCopyToOutputDirectoryItems ... into three copy targets, which run from
CopyFilesToOutputDirectory" — the three copy targets are actually invoked via_CopySourceItemsToOutputDirectory(a dependency ofCopyFilesToOutputDirectory). Harmless simplification.
Nice, well-sourced addition. 👍
- Soften the IfDifferent description to avoid overclaiming: it skips when "unchanged per MSBuild's heuristic" (timestamp + size, not a content hash), rather than "identical"/full Always equivalence. - Correct the target-flow wording: the three copy targets run as dependencies of _CopySourceItemsToOutputDirectory (invoked by CopyFilesToOutputDirectory). - Restore the USE FOR / DO NOT USE FOR routing pattern for the skill's frontmatter description, matching sibling skills. - Reclaim skill-menu budget headroom (per maintainer note) by tightening the verbose property-patterns and target-authoring descriptions; dotnet-msbuild rendered menu is now ~14,897/15,000 chars. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 881d26ad-87b7-48e3-8ec6-043163944437
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 881d26ad-87b7-48e3-8ec6-043163944437
Evangelink
left a comment
There was a problem hiding this comment.
Re-reviewed after the follow-up commits — all three points from my prior review are addressed, and I re-verified the changes:
- Budget headroom reclaimed. Trimming
property-patternsandtarget-authoringdescriptions offsets the now-richercopy-to-output-directorydescription. Recomputed with the validator's exactRenderedSkillMenuCostformula: dotnet-msbuild is now 14,901 / 15,000 chars (~99 headroom, up from ~47). Fits with a bit more room. - USE FOR / DO NOT USE FOR restored on the new skill's description — matches sibling convention.
- Target-flow wording corrected and accurate. Verified against the common targets:
CopyFilesToOutputDirectory→_CopySourceItemsToOutputDirectory→ the three copy targets (_CopyOutOfDateSourceItemsToOutputDirectory,_CopyOutOfDateSourceItemsToOutputDirectoryAlways,_CopyDifferingSourceItemsToOutputDirectory). IfDifferentdescription softened to correctly frameSkipUnchangedFilesas a timestamp+size heuristic (not a content hash) — accurate.- "an SQLite" article fix — good catch.
All previously-verified technical claims still hold. LGTM. 👍
|
👋 @YuliiaKovalova — this PR has 1 unresolved review thread(s). When you're ready, please address the feedback and push an update; the triage bot will pick up the next state automatically. (Add the |
Evangelink
left a comment
There was a problem hiding this comment.
Approving — no changes since my last review (head 7b047f2, already verified). Technical claims check out against MSBuild source, skill-menu budget fits (14,901/15,000), and all earlier feedback was addressed. LGTM. 👍
Skill Validation Results
[1] (Isolated) Quality unchanged but weighted score is -18.1% due to: judgment, tokens (108549 → 227575), time (66.4s → 83.7s) Model: claude-opus-4.6 | Judge: claude-opus-4.6 🔍 Full Results - additional metrics and failure investigation steps
|
Summary
Adds a focused
dotnet-msbuildskill —copy-to-output-directory— documenting how to choose aCopyToOutputDirectory/CopyToPublishDirectorymode, including theIfDifferentmode and the$(SkipUnchangedFilesOnCopyAlways)property introduced in MSBuild 17.13 / .NET SDK 9.0.2xx by dotnet/msbuild#11052.No existing skill covered this feature — it was only mentioned tangentially in
incremental-buildandmsbuild-antipatterns.What the skill covers
Never/PreserveNewest/Always/IfDifferent) with a comparison table.Alwaysis a recurring per-build performance hit, and the destination-mutation scenario it was historically used for.IfDifferentsemantics: copies when source and destination differ in either direction (newer or older, or size differs), via theCopytask'sSkipUnchangedFiles="true"(timestamp + size comparison).$(SkipUnchangedFilesOnCopyAlways)property for a bulk, non-invasive opt-in on legacyAlwaysitems.ProjectReference, and the MSBuild 17.13 / .NET SDK 9.0.2xx+ version requirement.Changes
plugins/dotnet-msbuild/skills/copy-to-output-directory/SKILL.mdmsbuild,msbuild-code-review, andbuild-perfagent files.Validation
markdownlint-cli2passes with 0 errors on the new file.